/*
 * Copyright (C) 2017 Piotr Wittchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.pwittchen.reactivenetwork.library.rx2;

import com.github.pwittchen.reactivenetwork.library.rx2.model.NetworkState;

import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.functions.Predicate;

import ohos.net.NetCapabilities;

/**
 * ConnectivityPredicate is a class containing predefined methods, which can be used for filtering
 * reactive streams of network connectivity
 */
public final class ConnectivityPredicate {
    private ConnectivityPredicate() {
    }

    /**
     * Filter, which returns true if at least one given state occurred
     *
     * @param networkStates NetworkInfo.State, which can have one or more states
     * @return true if at least one given state occurred
     */
    public static Predicate<Connectivity> hasState(final NetworkState... networkStates) {
        return new Predicate<Connectivity>() {
            @Override
            public boolean test(@NonNull Connectivity connectivity) throws Exception {
                for (NetworkState networkState : networkStates) {
                    if (connectivity.getNetworkState() == networkState) {
                        return true;
                    }
                }
                return false;
            }
        };
    }

    /**
     * Filter, which returns true if at least one given type occurred
     *
     * @param capabilities int, which can have one or more types
     * @return true if at least one given type occurred
     */
    public static Predicate<Connectivity> hasType(final NetCapabilities... capabilities) {
        final NetCapabilities[] extendedCapabilities = appendUnknownNetCapabilitiesToCapabilities(capabilities);
        return new Predicate<Connectivity>() {
            @Override
            public boolean test(@NonNull Connectivity connectivity) throws Exception {
                for (NetCapabilities netCapabilities : extendedCapabilities) {
                    if (connectivity.getNetworkState().getNetworkCapabilities() == netCapabilities) {
                        return true;
                    }
                }
                return false;
            }
        };
    }

    /**
     * Returns network types from the input with additional unknown type,
     * what helps during connections filtering when device
     * is being disconnected from a specific network
     *
     * @param netCapabilities of the network as an array of ints
     * @return types of the network with unknown type as an array of ints
     */
    protected static NetCapabilities[] appendUnknownNetCapabilitiesToCapabilities(NetCapabilities[] netCapabilities) {
        int count = 0;
        final NetCapabilities[] extendedTypes = new NetCapabilities[netCapabilities.length + 1];
        for (NetCapabilities capabilities : netCapabilities) {
            extendedTypes[count] = capabilities;
            count++;
        }
        extendedTypes[count] = new NetCapabilities();
        return extendedTypes;
    }
}
